﻿using Hydrogen.MathExt.Expression.Functions;
using Hydrogen.MathExt.Expression.Functions.Operators;
using System;
using System.Collections.Generic;

namespace Hydrogen.MathExt.Expression
{
    public interface IExpressionEvaluator
    {
        double Evaluate(Dictionary<string, double> variables);
    }

    /// <summary>
    /// 执行逆波兰表达式计算<br/>
    /// 处理变量查找和函数调用<br/>
    /// 执行基本数学运算<br/>
    /// 提供错误处理（除零、未定义变量等）<br/>
    /// </summary>
    internal class ExpressionEvaluator : IExpressionEvaluator
    {
        private List<Token> _rpn;
        public ExpressionEvaluator(List<Token> rpn)
        {
            this._rpn = rpn;
        }
        public double Evaluate(Dictionary<string, double> variables)
        {
            if (variables == null) variables = new Dictionary<string, double>();
            return Evaluate(this._rpn, variables);
        }

        public static double Evaluate(List<Token> rpn, Dictionary<string, double> variables)
        {
            Stack<double> stack = new Stack<double>();

            foreach (Token token in rpn)
            {
                switch (token.Type)
                {
                    case TokenType.Number:
                    case TokenType.Constant:
                        stack.Push(token.NumericValue.Value);
                        break;

                    case TokenType.Variable:
                        if (variables != null && variables.TryGetValue(token.Value, out double value))
                        {
                            stack.Push(value);
                        }
                        else
                        {
                            throw new KeyNotFoundException($"Undefined variable: {token.Value}");
                        }
                        break;

                    case TokenType.Function:
                        if (FunctionBase.TryGetFunction(token.Value, out var function))
                        {
                            double[] args = new double[function.ArgCount];
                            for (int i = args.Length - 1; i >= 0; i--)
                            {
                                args[i] = stack.Pop();
                            }
                            stack.Push(function.Evaluate(args));
                        }
                        else
                        {
                            throw new KeyNotFoundException($"Undefined function: {token.Value}");
                        }
                        break;

                    case TokenType.Operator:
                        if (stack.Count < 2)
                        {
                            throw new InvalidOperationException($"Insufficient operands for operator: {token.Value}");
                        }

                        double right = stack.Pop();
                        double left = stack.Pop();
                        stack.Push(ApplyOperator(token.Value, left, right));
                        break;
                }
            }

            if (stack.Count != 1)
            {
                throw new InvalidOperationException("Invalid expression format");
            }

            return stack.Pop();
        }

        private static double ApplyOperator(string op, double left, double right)
        {
            if (!OperatorBinaryBase.TryGetOperator(op, out var constants))
                throw new ArgumentException($"不支持运算符: {op}");

            return constants.Evaluate(left, right);
        }
    }
}
